package com.app.protocol.entity;

import java.util.Date;

import com.app.exception.GPSDataVertifyFailException;
import com.app.protocol.gps.GpsAngleLatiLongDscr;
import com.app.protocol.gps.GpsAntennaDriver;
import com.app.protocol.gps.GpsLatitude;
import com.app.protocol.gps.GpsLongtitude;
import com.app.protocol.gps.GpsStatusAlarm;
import com.app.protocol.gps.GpsStatusClient;

import soft.common.*;
import soft.ifs.IByteBuff;
import soft.ifs.IBytesBuild;
import soft.ifs.IParse;
import soft.net.exception.DataIsNullException;
import soft.net.exception.DecodeDataFailException;
import soft.net.model.AReadNetStream;
import soft.net.model.CusByteStream;

/**
 * GPS协议
 * 
 * 时间A4 + 纬度B4+经度C4 + 速度D1 +方向东西经、南北纬E1+ 定位状态以及天线状态司机编码F1 + 里程G3 + 终端状态H3 +
 * 报警位I4 + 异或校验J1
 * 
 * @author fanpei
 *
 */
public class ProtocolGPS extends AReadNetStream implements IParse, IBytesBuild {

	/**
	 * 大小固定为26字节
	 */
	public static final int SIZE = 26;

	private static final long GMT_TIMESTAMP_From2000_1_1 = 946684800000L;// 距离2000.1.1日时间差

	/**
	 * (0-3) 时间
	 * 
	 * 表示从2000 年1 月1 日凌晨开始多少秒 （单位秒，格林威治时间）例如：0x07FCE8FF 表示 04 年3 月31 日02 点27 分11
	 * 秒（注意是格林威治时间）
	 * 
	 * @Size 4个字节
	 */
	private byte[] pasttime;
	private Date date;// 格林威治转本地之后时间

	/**
	 * (4-7) 纬度
	 * 
	 * @Size 4 个字节
	 */
	private byte[] latitudes;
	private double latitude;// 纬度小数表示

	/**
	 * (8-11) 经度
	 * 
	 * @Size 4 个字节
	 */
	private byte[] longitudes;
	private double longitude;// 经度小数表示

	/**
	 * (12) 速度：1 个字节，（0x00-0x7F 连续）单位节 注意预留D7 作为冗余位（日后定义使用）
	 */
	private byte speed;

	/**
	 * (13) 方向＋GPS 标志：1 个字节（排列顺序：D7D6D5D4D3D2D1D0），其中D5D4D3D2D1D0 六位（0～36）用于表示
	 * 方向，单位为10°（正北为0°顺时针转）
	 * 
	 * @D7D6 D7D6 两位用于表示GPS 标志：(范围0-3)，
	 * @Define 具体定义为： 北纬东经(0) 北纬西经(1) 南纬东经(2) 南纬西经(3)
	 * @D6 D6 表示经度变化01 0 1
	 * @D7 D7表示纬度变化 0 0 1 1
	 */
	private byte direcGPSFlag;

	private GpsAngleLatiLongDscr gpsAngleLocation;

	/**
	 * (14) GPS 天线状态＋定位状态＋司机编号
	 */
	private byte gpsStatusDriverCode;
	private GpsAntennaDriver gpsStatusDriver;

	/**
	 * (15-17) 累积里程
	 * 
	 * @dsrc 0x000000－0xFFFFFF，单位1/76 公里； 例如：0x00001D 表示累积里程为：0x1D/76=0.3816公里
	 * 
	 * @Size 3 个字节
	 */
	private byte[] accumulatedMiles;
	private float totalMile;// 公里的小数表示

	/**
	 * (18-20)终端状态
	 * 
	 * @Size 3 个字节
	 */
	private byte[] clientStatuss;
	private GpsStatusClient clientStatus;

	/**
	 * (21-24) 报警
	 * 
	 * @Size 4 个字节
	 */
	private byte[] alarmFlags;
	private GpsStatusAlarm alarmStatus;

	/**
	 * (25) 异或取反校验
	 */
	private byte parity;

	/**
	 * default constructor
	 */
	public ProtocolGPS() {
		objinit();
	}

	/**
	 * parse constructor
	 * 
	 * @param srcBytes 原始bytes
	 */
	public ProtocolGPS(byte[] srcBytes) {
		objinit();
		this.srcBytes = srcBytes;
	}

	/**
	 * 对象初始化
	 */
	private void objinit() {
		pasttime = new byte[4];
		latitudes = new byte[4];
		longitudes = new byte[4];
		accumulatedMiles = new byte[3];
		clientStatuss = new byte[3];
		alarmFlags = new byte[4];
	}

	/**
	 * 数据校验
	 * 
	 * @throws GPSDataVertifyFailException
	 */
	public void validate() throws GPSDataVertifyFailException {
		byte xorResult = buildCheckBit();
		if (xorResult != parity) {
			throw new GPSDataVertifyFailException("ProtocolGPS validate fail,the parity is not same!");
		}

	}

	private byte[] srcBytes;// 解析用变量

	@Override
	public void parse() throws DecodeDataFailException, DataIsNullException {

		if (srcBytes == null || srcBytes.length == 0) {
			throw new DataIsNullException("ProtocolGPS parse:srcBytes is null or empty!");
		} else{
			System.out.println("ProtocolGPS:"+BytesHexStrTranslate.bytesToHexFun1(srcBytes) );
		}
		IByteBuff in = null;
		try {
			in = new CusByteStream(srcBytes);
			if (in.readableBytes() == SIZE) {
				in.readBytes(pasttime);
				in.readBytes(latitudes);
				in.readBytes(longitudes);
				speed = in.readByte();
				direcGPSFlag = in.readByte();
				gpsStatusDriverCode = in.readByte();
				in.readBytes(accumulatedMiles);
				in.readBytes(clientStatuss);
				in.readBytes(alarmFlags);
				parity = in.readByte();
			}

		} finally {
			if (in != null) {
				in.release();
			}
		}
		clear();
		// 转换数据部分
		int timepass = BConvrtUtil.byteToInt(pasttime);
		date = new Date(Long.valueOf(timepass)*1000 + GMT_TIMESTAMP_From2000_1_1);
		this.longitude = DuFenMiaoToLonLat.DuFenMiaoToLon(longitudes);
		this.latitude = DuFenMiaoToLonLat.DuFenMiaoToLat(latitudes);

		speed = BConvrtUtil.ChangeHighLowLoc(speed);// 高低位调换
		gpsAngleLocation = new GpsAngleLatiLongDscr(gpsStatusDriverCode);
		gpsStatusDriver = new GpsAntennaDriver(gpsStatusDriverCode);
		totalMile = BConvrtUtil.byteToInt(accumulatedMiles) / 76;
		clientStatus = new GpsStatusClient(clientStatuss);
		alarmStatus = new GpsStatusAlarm(alarmFlags);

		System.out.println(DateUtils.formatDateTime(date));
		System.out.println(longitude);
		System.out.println(latitude);
		System.out.println(speed);
		System.out.println(totalMile);
		System.out.println(alarmStatus.getLockStatus().name());
	}

	@Override
	public void clear() {
		srcBytes = null;
	}

	@Override
	public byte[] buildBytes() {
		byte[] sends = new byte[SIZE];
		System.arraycopy(pasttime, 0, sends, 0, 4);
		System.arraycopy(latitudes, 0, sends, 4, 4);
		System.arraycopy(longitudes, 0, sends, 8, 4);
		sends[12] = speed;
		sends[13] = direcGPSFlag;
		sends[14] = gpsStatusDriverCode;
		System.arraycopy(accumulatedMiles, 0, sends, 15, 3);
		System.arraycopy(clientStatuss, 0, sends, 18, 3);
		System.arraycopy(alarmFlags, 0, sends, 21, 4);
		sends[25] = buildCheckBit();
		return sends;
	}

	// *********************************数据获取(转换)******************************************//
	/**
	 * 获取格林威治时间
	 * 
	 * @return
	 */
	public Date getDate() {
		return date;
	}

	public double getLatitude() {
		return latitude;
	}

	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}

	public double getLongitude() {
		return longitude;
	}

	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}

	public byte getSpeed() {
		return speed;
	}

	public GpsAngleLatiLongDscr getGpsAngleLocation() {
		return gpsAngleLocation;
	}

	public GpsAntennaDriver getGpsStatusDriver() {
		return gpsStatusDriver;
	}

	public float getTotalMile() {
		return totalMile;
	}

	public byte[] getClientStatuss() {
		return clientStatuss;
	}

	public GpsStatusClient getClientStatus() {
		return clientStatus;
	}

	public GpsStatusAlarm getAlarmStatus() {
		return alarmStatus;
	}

	public byte getDirecGPSFlag() {
		return direcGPSFlag;
	}

	public void setDirecGPSFlag(byte direcGPSFlag) {
		this.direcGPSFlag = direcGPSFlag;
	}

	/**
	 * 获取异校验位
	 * 
	 * @return
	 */
	private byte buildCheckBit() {
		byte xorResult = BitCheckUtil.xorCheck(pasttime[0], pasttime);
		xorResult = BitCheckUtil.xorCheck(xorResult, latitudes);
		xorResult = BitCheckUtil.xorCheck(xorResult, longitudes);
		xorResult = BitCheckUtil.xorCheck(xorResult, speed);
		xorResult = BitCheckUtil.xorCheck(xorResult, direcGPSFlag);
		xorResult = BitCheckUtil.xorCheck(xorResult, gpsStatusDriverCode);
		xorResult = BitCheckUtil.xorCheck(xorResult, accumulatedMiles);
		xorResult = BitCheckUtil.xorCheck(xorResult, clientStatuss);
		xorResult = BitCheckUtil.xorCheck(xorResult, alarmFlags);
		xorResult = (byte) (~xorResult);
		return xorResult;
	}

}
